﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using OracleProvider.Enums;
using DatabaseExtension.ConnectionString;
using DatabaseExtension;

namespace OracleProvider.ConnectionString
{
    /// <summary>
    /// Provide database connection information for Oracle Database Server
    /// <see cref="http://docs.oracle.com/cd/B13789_01/win.101/b10117/features001.htm"/>
    /// </summary>
    public class OracleConnectionInfo : ConnectionInfo
    {
        public Oracle.DataAccess.Client.OracleConnectionStringBuilder OracleConnectionStringBuilder
        {
            get
            {
                return base.ConnectionStringBuilder as Oracle.DataAccess.Client.OracleConnectionStringBuilder;
            }
        }
        #region ConnectionStringBuilder Derived Parameter
        /// <summary>
        /// Maximum life time (in seconds) of the connection
        /// Default Value: 0.
        /// </summary>
        public int ConnectionLifeTime
        {
            get
            {
                return this.OracleConnectionStringBuilder.ConnectionLifeTime;
            }
            set
            {
                this.OracleConnectionStringBuilder.ConnectionLifeTime = value;
            }
        }
        /// <summary>
        /// Maximum time (in seconds) to wait for a free connection from the pool
        /// Default Value: 15.
        /// </summary>
        public int ConnectionTimeout
        {
            get
            {
                return this.OracleConnectionStringBuilder.ConnectionTimeout;
            }
            set
            {
                this.OracleConnectionStringBuilder.ConnectionTimeout = value;
            }
        }
        /// <summary>
        /// Within a .NET stored procedure, an implicit database connection is available for use to access Oracle data. 
        /// This implicit database connection should be used rather than establishing a user connection because the 
        /// implicit database connection is already established by the caller of the .NET stored procedure, thereby minimizing resource usage.
        /// 
        /// To obtain an OracleConnection object in a .NET stored procedure that represents the implicit database connection, set the 
        /// ConnectionString property of the OracleConnection object to "context connection=true" and invoke the Open method. 
        /// No connection string attributes can be used with "context connection=true", except the Statement Cache Size attribute
        /// 
        /// <seealso cref="http://docs.oracle.com/html/E10927_01/extenRest.htm"/>
        /// </summary>
        public Boolean ContextConnection
        {
            get
            {
                return this.OracleConnectionStringBuilder.ContextConnection;
            }
            set
            {
                this.OracleConnectionStringBuilder.ContextConnection = value;
            }
        }
        /// <summary>
        /// Oracle allows database administrators to connect to an Oracle Database with either SYSDBA or SYSOPER privileges.
        /// </summary>
        public OracleDBAPrivilege DBAPrivilege
        {
            get
            {
                return (OracleDBAPrivilege)this.OracleConnectionStringBuilder.DBAPrivilege.StringToEnum(typeof(OracleDBAPrivilege));
            }
            set
            {
                this.OracleConnectionStringBuilder.DBAPrivilege = value.EnumToString();
            }
        }
        /// <summary>
        /// Controls the number of connections that are closed when an excessive amount of established connections are unused.
        /// Default Value: 1
        /// </summary>
        public int DecrPoolSize
        {
            get
            {
                return this.OracleConnectionStringBuilder.DecrPoolSize;
            }
            set
            {
                this.OracleConnectionStringBuilder.DecrPoolSize = value;
            }
        }
        /// <summary>
        /// A Enum that represents the value of the supplied attribute. Values are case-insensitive. Possible values are: dynamic, true, false, yes, and no.
        /// Default Value: True
        /// </summary>
        public OracleEnlist Enlist
        {
            get
            {
                return (OracleEnlist)this.OracleConnectionStringBuilder.Enlist.StringToEnum(typeof(OracleEnlist));
            }
            set
            {
                this.OracleConnectionStringBuilder.Enlist = value.EnumToString();
            }
        }
        /// <summary>
        /// Enables ODP.NET connection pool to proactively remove connections from the pool when an 
        /// Oracle RAC service, service member, or node goes down. Works with RAC, Data Guard, or a single database instance.
        /// Default Value: False
        /// </summary>
        public Boolean HAEvents
        {
            get
            {
                return this.OracleConnectionStringBuilder.HAEvents;
            }
            set
            {
                this.OracleConnectionStringBuilder.HAEvents = value;
            }
        }
        /// <summary>
        /// Controls the number of connections that are established when all the connections in the pool are used
        /// Default Value: 5
        /// </summary>
        public int IncrPoolSize
        {
            get
            {
                return this.OracleConnectionStringBuilder.IncrPoolSize;
            }
            set
            {
                this.OracleConnectionStringBuilder.IncrPoolSize = value;
            }
        }
        /// <summary>
        /// Enables ODP.NET connection pool to balance work requests across Oracle RAC instances based on the load balancing advisory and service goal.
        /// Default Value: False
        /// </summary>
        public Boolean LoadBalancing
        {
            get
            {
                return this.OracleConnectionStringBuilder.LoadBalancing;
            }
            set
            {
                this.OracleConnectionStringBuilder.LoadBalancing = value;
            }
        }
        /// <summary>
        /// Maximum number of connections in a pool
        /// Default Value: 100
        /// </summary>
        public int MaxPoolSize
        {
            get
            {
                return this.OracleConnectionStringBuilder.MaxPoolSize;
            }
            set
            {
                this.OracleConnectionStringBuilder.MaxPoolSize = value;
            }
        }
        /// <summary>
        /// Caches metadata information.
        /// Default Value: True
        /// </summary>
        public Boolean MetadataPooling
        {
            get
            {
                return this.OracleConnectionStringBuilder.MetadataPooling;
            }
            set
            {
                this.OracleConnectionStringBuilder.MetadataPooling = value;
            }
        }
        /// <summary>
        /// Minimum  number of connections in a pool
        /// Default Value: 1
        /// </summary>
        public int MinPoolSize
        {
            get
            {
                return this.OracleConnectionStringBuilder.MinPoolSize;
            }
            set
            {
                this.OracleConnectionStringBuilder.MinPoolSize = value;
            }
        }
        /// <summary>
        /// Retrieval of the password in the connection string.
        /// Default Value: False
        /// </summary>
        public Boolean PersistSecurityInfo
        {
            get
            {
                return this.OracleConnectionStringBuilder.PersistSecurityInfo;
            }
            set
            {
                this.OracleConnectionStringBuilder.PersistSecurityInfo = value;
            }
        }
        /// <summary>
        /// Enables or disables connection pooling
        /// Default Value: true
        /// </summary>
        public Boolean Pooling
        {
            get
            {
                return this.OracleConnectionStringBuilder.Pooling;
            }
            set
            {
                this.OracleConnectionStringBuilder.Pooling = value;
            }
        }
        /// <summary>
        /// This feature enables applications to use local transactions with
        /// System.Transactions where previous versions of ODP.NET supported only
        /// distributed transactions with System.Transactions. If the
        /// PromotableTransaction registry does not exist, the default value of
        /// "promotable" is used. If "promotable" is specified, first and subsequent
        /// connections opened in the same TransactionScope will enlist in the same
        /// distributed transaction. If "local" is specified, the first connection
        /// opened in the TransactionScope will use a local transaction. If any
        /// subsequent connections are opened within the same TransactionScope,
        /// an exception will be thrown. If there are connections opened already
        /// in the TransactionScope and an OracleConnection with
        /// "Promotable Transaction=local" is attempted to be opened within the same
        /// TransactionScope, an exception will also be thrown. 
        /// </summary>
        public String PromotableTransaction
        {
            get
            {
                return this.OracleConnectionStringBuilder.PromotableTransaction;
            }
            set
            {
                this.OracleConnectionStringBuilder.PromotableTransaction = value;
            }
        }
        /// <summary>
        /// Password of the proxy user
        /// Default Value: Empty String
        /// </summary>
        public String ProxyPassword
        {
            get
            {
                return this.OracleConnectionStringBuilder.ProxyPassword;
            }
            set
            {
                this.OracleConnectionStringBuilder.ProxyPassword = value;
            }
        }
        /// <summary>
        /// ODP.NET applications can be self-tuned for performance optimization. ODP.NET dynamically monitors application queries during runtime.
        /// </summary>
        public Boolean SelfTuning
        {
            get
            {
                return this.OracleConnectionStringBuilder.SelfTuning;
            }
            set
            {
                this.OracleConnectionStringBuilder.SelfTuning = value;
            }
        }
        /// <summary>
        /// Statement cache purged when the connection goes back to the pool.
        /// Default Value: False
        /// </summary>
        public Boolean StatementCachePurge
        {
            get
            {
                return this.OracleConnectionStringBuilder.StatementCachePurge;
            }
            set
            {
                this.OracleConnectionStringBuilder.StatementCachePurge = value;
            }
        }
        /// <summary>
        /// Specifies the current size of the statement cache associated with this connection.
        /// </summary>
        /// <remarks>
        /// If self tuning is not enabled, then the default value of this property depends upon the statement 
        /// cache size specified in the connection string, application configuration file, or the registry. 
        /// If none of these values are specified, then a default value of 0 is used.
        /// 
        /// If self tuning is enabled, then the property value is adjusted automatically. 
        /// Any values specified in the connection string, application configuration file, or the registry are ignored.
        /// </remarks>
        public int StatementCacheSize
        {
            get
            {
                return this.OracleConnectionStringBuilder.StatementCacheSize;
            }
            set
            {
                this.OracleConnectionStringBuilder.StatementCacheSize = value;
            }
        }
        /// <summary>
        /// Validation of connections coming from the pool.
        /// Default Value: False
        /// </summary>
        public Boolean ValidateConnection
        {
            get
            {
                return this.OracleConnectionStringBuilder.ValidateConnection;
            }
            set
            {
                this.OracleConnectionStringBuilder.ValidateConnection = value;
            }
        }
        #endregion
        /// <summary>
        /// Manage Oracle Sql Boolean through the Enumerator Flags. Set only if needed. Not setted flags are marked as False Values.
        /// </summary>
        public OracleFlags BooleanFlags
        {
            get
            {
                return this._BooleanFlags;
            }
            set
            {
                var tmp = this.OracleConnectionStringBuilder;
                tmp.ContextConnection = value.HasFlag(OracleFlags.ContextConnection);
                tmp.HAEvents = value.HasFlag(OracleFlags.HAEvents);
                tmp.LoadBalancing = value.HasFlag(OracleFlags.LoadBalancing);
                tmp.MetadataPooling = value.HasFlag(OracleFlags.MetadataPooling);
                tmp.PersistSecurityInfo = value.HasFlag(OracleFlags.PersistSecurityInfo);
                tmp.Pooling = value.HasFlag(OracleFlags.Pooling);
                tmp.SelfTuning = value.HasFlag(OracleFlags.SelfTuning);
                tmp.StatementCachePurge = value.HasFlag(OracleFlags.StatementCachePurge);
                tmp.ValidateConnection = value.HasFlag(OracleFlags.ValidateConnection);
                this._BooleanFlags = value;
            }
        }
        private OracleFlags _BooleanFlags;

        /// <summary>
        /// Create new encrpyted Oracle SQL connection.
        /// </summary>
        /// <param name="server">Path to the database.</param>
        /// <param name="password">Password for the user specified by User Id.</param>
        public OracleConnectionInfo(String server, String user, String pwd)
            : base(Databases.Oracle, server, user, pwd)
        {

        }
        /// <summary>
        /// Creat new OracleConnectionStringBuilder based on Connection String Builder.
        /// </summary>
        /// <param name="cecsb">SQL Compact Edition Connection String Builder</param>
        public OracleConnectionInfo(Oracle.DataAccess.Client.OracleConnectionStringBuilder ocsb)
            : base(Databases.Oracle, ocsb)
        {
        }
        /// <summary>
        /// Create new Oracle Connection String Builder
        /// </summary>
        /// <returns></returns>
        protected override System.Data.Common.DbConnectionStringBuilder GetConnectionStringbuilder()
        {
            this.ClientFactory = Oracle.DataAccess.Client.OracleClientFactory.Instance;
            var result = this.ClientFactory.CreateConnectionStringBuilder() as Oracle.DataAccess.Client.OracleConnectionStringBuilder;
            result.DataSource = this.Server;
            if (String.IsNullOrEmpty(base.UserName) == false)
                result.UserID = this.UserName;
            if (String.IsNullOrEmpty(base.Password) == false)
                result.Password = this.Password;
            return result;
        }
        /// <summary>
        /// Create new Db Parameter
        /// </summary>
        /// <param name="name">Parameter Name</param>
        /// <param name="value">Parameter Value</param>
        /// <param name="type">Use Oracle.DataAccess.Client.OracleDbType for inserted parameter</param>
        /// <param name="isNullable">if true, empty object will be converted to DbNull.Value</param>
        /// <param name="Size">Object Size.</param>
        /// <returns>Return new DbParameter</returns>
        public override System.Data.Common.DbParameter CreateParameter(string name, object value, object type, bool isNullable, int Size = 0)
        {
            var param = this.ClientFactory.CreateParameter() as Oracle.DataAccess.Client.OracleParameter;
            param.ParameterName = name;
            param.Value = (isNullable && value == null) ? DBNull.Value : value;
            param.Size = Size;
            if (type is System.Data.SqlDbType)
                param.OracleDbType = (Oracle.DataAccess.Client.OracleDbType)type;
            else if (type is System.Data.DbType)
                param.DbType = (System.Data.DbType)type;
            else
                throw new ArgumentException("Could not recognize Db Type");
            param.IsNullable = isNullable;
            return param;
        }
        /// <summary>
        /// Create new Db Parameter. Autodetect parameter value type
        /// </summary>
        /// <param name="name">Parameter Name</param>
        /// <param name="value">Parameter Value</param>
        /// <param name="isNullable">if true, empty object will be converted to DbNull.Value</param>
        /// <param name="Size">Object Size.</param>
        /// <returns>Return new DbParameter</returns>
        public override System.Data.Common.DbParameter CreateParameter(string name, object value, bool isNullable, int Size = 0)
        {
            return this.CreateParameter(name, value, DbTypeConverter.ToDbType(value), isNullable, Size);
        }
    }
}
